package br.com.iswe.gerador.velocity.info;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jdom.Attribute;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

import br.com.iswe.core.exp.ISWEConfigurationException;

@SuppressWarnings("unchecked")
public class ArquivosConfig {
	
	private static final String FALSE = "false";
	private static final String OVERRIDE = "override";
	private static final String NAME = "name";
	private static final String INCLUDE = "include";
	private static final String CATEGORY = "category";
	private static final String ALL = "all";
	private static final String PATTERN = "pattern";
    private static final String EXCLUDE = "exclude";
	
	private ClassLoader runnerClassLoader = null;
	
	private Category categoryAll = new Category();
	private Map<String, Category> mapCategory = new HashMap<String, Category>();
	
	public ArquivosConfig(String configXml, ClassLoader runnerClassLoader){
		this.runnerClassLoader = runnerClassLoader;
		loadXmlConfig(configXml);
	}

	private void loadXmlConfig(String configXml) {
        try {
            //carrega o arquivo de configuracoes XML.
            SAXBuilder builder = new SAXBuilder();
            // Execute the XML parser
            Document doc = builder.build(runnerClassLoader.getResourceAsStream(configXml));
            //Carrega as configuracoes gerais.
            List<Element> patternsExclude = getElements(doc.getRootElement(), EXCLUDE);
            List<Element> patternsInclude = getElements(doc.getRootElement(), INCLUDE);
            categoryAll.setPatternsExclude(patternsExclude);
            categoryAll.setPatternsInclude(patternsInclude);
            categoryAll.setName(ALL);
            
            //carrega os valores por categoria.
            List<Element> categorias = doc.getRootElement().getChildren(CATEGORY);
            for(Element cat : categorias){
                Attribute name  = cat.getAttribute(NAME);
                patternsExclude = getElements(cat, EXCLUDE);
                patternsInclude = getElements(cat, INCLUDE);
                Category category = new Category();
                category.setName(name.getValue());
                category.setPatternsExclude(patternsExclude);
                category.setPatternsInclude(patternsInclude);
                mapCategory.put(name.getValue(), category);
            }
            
        }
        catch (JDOMException e) {
            throw new ISWEConfigurationException("Nao foi possivel ler o arquivo xml: " + configXml, e);
        }
        catch (IOException e) {
            throw new ISWEConfigurationException("Nao foi possivel encontrar ou abrir o arquivo: " + configXml, e);
        }
        
    }
	
	
	private List<Element> getElements(Element element, String nodeName) {
		List<Element> exclude = element.getChildren(nodeName);
		List<Element> patterns = new ArrayList<Element>();
		//varre a lista de elementos exclude
        for(Element elemento : exclude){
            patterns.add(elemento);
        }
        return patterns;
	}

	static class Category{
		private List<Element> patternsExclude = null;
		private List<Element> patternsInclude = null;
		private String name = null;
		
		public List<Element> getPatternsExclude() {
			return patternsExclude;
		}
		public void setPatternsExclude(List<Element> patternsExclude) {
			this.patternsExclude = patternsExclude;
		}
		
		public List<Element> getPatternsInclude() {
			return patternsInclude;
		}
		public void setPatternsInclude(List<Element> patternsInclude) {
			this.patternsInclude = patternsInclude;
		}
		public String getName() {
			return name;
		}
		public void setName(String name) {
			this.name = name;
		}
	}

	public Category getCategoryAll() {
		return categoryAll;
	}

	public void setCategoryAll(Category categoryAll) {
		this.categoryAll = categoryAll;
	}

	public Map<String, Category> getMapCategory() {
		return mapCategory;
	}

	public void setMapCategory(Map<String, Category> mapCategory) {
		this.mapCategory = mapCategory;
	}

	public boolean shouldGenerateFile(String arquivo, String categoryName) {
		Category category = null;
		boolean checkFileExists = false;
        if(ALL.equals(categoryName)){
        	category = getCategoryAll();
        }
        else{
        	category = getMapCategory().get(categoryName);
        }
        boolean shouldGenerateFile = true;
        
        //verifica os padroes de inclusao
        //caso tenha algum pattern de 'include' apenas os arquivos q batem com esse padrao serao gerados.
        if(category.getPatternsInclude().size() > 0){
        	shouldGenerateFile = false;
	        for(Element element: category.getPatternsInclude()){
	            if(arquivo.matches(getPattern(element))){
	                shouldGenerateFile = true;
	                //verifica se deve verificar o sobrescrita
	                if(FALSE.equals( element.getAttributeValue(OVERRIDE) )){
	                	checkFileExists = true;
	                }	                
	                break;
	            }
	        }
        }
        
        // verifica os padroes de exclusao
        if(shouldGenerateFile){
            //varre a lista de patterns
            for(Element element: category.getPatternsExclude()){
                if(arquivo.matches(getPattern(element))){
                    return false;
                }
            }
        }
        
        //verifica se deve verificar se o arquivo existe
        if( checkFileExists ){
	        //terceiro caso deve ser ignorado verifica se o arquivo ja existe
	       File checkFile = new File(arquivo);
	       shouldGenerateFile = !checkFile.exists();
        }
        return shouldGenerateFile;
	}

	private String getPattern(Element element) {
		Attribute att = element.getAttribute(PATTERN);
		return att.getValue();
	}	
}
